#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string.h>

#define WIDTH 50
#define HEIGHT 20

int map[HEIGHT][WIDTH];
int snakeX[100], snakeY[100];
int foodX, foodY;
int score = 0;
int highScore = 0;
int snakeLength = 1;
int direction = 1; // 1: 右, 2: 下, 3: 左, 4: 上
int gameOver = 0;

int speed = 200; // 初始速度
// 函数原型声明
void printsnake();
void welcometogame();
void displayHighScore();
void initsnake();
void createfood();
void speedup();
void speeddown();
void snakemove();
void endGame();
void resetGame();
void showInstructions();



void printsnake() {
	system("cls");
	printf("\n\n");
	printf("      ########    ##    ##    ########   ##   ##    ########\n");
	printf("    ##         ## #  ##    ##    ##    ##  ##     ##      \n");
	printf("    ######    ##  # ##    ########    ####      ######   \n");
	printf("        ##   ##   ###    ##    ##    ## ##     ##      \n");
	printf("  ######## ##    ##    ##    ##    ##   ##    ########\n");
	printf("\n");
	printf("      ======================================\n");
	printf("      ||                                 ||\n");
	printf("      ||       1. 开始游戏               ||\n");
	printf("      ||       2. 最高分数               ||\n");
	printf("      ||       3. 退出游戏               ||\n");
	printf("      ||       4. 游戏帮助               ||\n");
	printf("      ||                                 ||\n");
	printf("      ======================================\n");
}

void welcometogame() {
	printsnake();
	while (1) {
		if (_kbhit()) {
			char ch = _getch();
			if (ch == '1') {
				initsnake();
				createfood();
				snakemove();
				break;
			} else if (ch == '2') {
				displayHighScore();
			} else if (ch == '3') {
				exit(0);
			} else if (ch == '4') {
				showInstructions();
			}
		}
	}
}

void displayHighScore() {
	system("cls");
	FILE *file = fopen("save.txt", "r");
	if (file != NULL) {
		fscanf(file, "%d", &highScore);
		fclose(file);
	}
	printf("最高分数: %d\n", highScore);
	printf("按任意键返回...\n");
	_getch();
	welcometogame();
}

void initsnake() {
	snakeX[0] = WIDTH / 2;
	snakeY[0] = HEIGHT / 2;

}

void createfood() {
	int valid = 0;
	while (!valid) {
		foodX = rand() % (WIDTH - 2) + 1;
		foodY = rand() % (HEIGHT - 2) + 1;
		valid = 1;
		for (int i = 0; i < snakeLength; i++) {
			if (snakeX[i] == foodX && snakeY[i] == foodY) {
				valid = 0;
				break;
			}
		}
	}
}

void speedup() {
	if (speed > 10) {
		speed -= 10;
	}
}

void speeddown() {
	speed += 30;
}

void snakemove() {
	int prevX, prevY;
	prevX = snakeX[0];
	prevY = snakeY[0];

	// 通过方向键更新蛇头位置
	if (direction == 1) {
		snakeX[0]++;
	} else if (direction == 2) {
		snakeY[0]++;
	} else if (direction == 3) {
		snakeX[0]--;
	} else if (direction == 4) {
		snakeY[0]--;
	}

	// 检测是否撞到边界
	if (snakeX[0] <= 0 || snakeX[0] >= WIDTH - 1 || snakeY[0] <= 0 || snakeY[0] >= HEIGHT - 1) {
		gameOver = 1;
	}

	// 检测是否撞到蛇身
	for (int i = 1; i < snakeLength; i++) {
		if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
			gameOver = 1;
			break;
		}
	}

	// 检测是否吃到食物
	if (snakeX[0] == foodX && snakeY[0] == foodY) {
		if (speed <= 320) {
			score += 2;
		} else {
			score += 1;
		}
		snakeLength++;
		createfood();
		speedup();
	} else {
		// 移动剩余蛇身
		for (int i = 1; i < snakeLength; i++) {
			int tempX = snakeX[i];
			int tempY = snakeY[i];
			snakeX[i] = prevX;
			snakeY[i] = prevY;
			prevX = tempX;
			prevY = tempY;
		}
	}

	// 绘制蟒蛇和食物
	for (int i = 0; i < HEIGHT; i++) {
		for (int j = 0; j < WIDTH; j++) {
			map[i][j] = 0;
		}
	}
	for (int i = 0; i < snakeLength; i++) {
		map[snakeY[i]][snakeX[i]] = 1;
	}
	map[foodY][foodX] = 2;

	system("cls");

	FILE *file = fopen("save.txt", "r");
	fscanf(file, "%d", &highScore);
	fclose(file);


	printf("当前分数: %d | 最高分数: %d | 当前速度: %d\n", score, highScore, speed);
	// 绘制上边界
	for (int i = 0; i < WIDTH + 2; i++) {
		printf("#");
	}
	printf("\n");

	// 获得句柄以控制蟒蛇与食物颜色
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);

	for (int i = 0; i < HEIGHT; i++) {
		printf("#");
		for (int j = 0; j < WIDTH; j++) {
			if (map[i][j] == 1) {
				SetConsoleTextAttribute(console, 14); // 令蟒蛇为黄色
				printf("*");
				SetConsoleTextAttribute(console, 15); // 重置为默认颜色
			} else if (map[i][j] == 2) {
				SetConsoleTextAttribute(console, 10); // 令食物为绿色
				printf("O");
				SetConsoleTextAttribute(console, 15); // 重置为默认颜色
			} else {
				printf(" ");
			}
		}
		printf("#\n");
	}

// 绘制下边界
	for (int i = 0; i < WIDTH + 2; i++) {
		printf("#");
	}
	printf("\n");

	// 检测游戏是否结束
	if (gameOver) {
		endGame();
	}

	// 检测键盘输入以改变方向
	if (_kbhit()) {
		char ch = _getch();
		if (ch == 'w' && direction != 2)
			direction = 4;
		else if (ch == 's' && direction != 4)
			direction = 2;
		else if (ch == 'a' && direction != 1)
			direction = 3;
		else if (ch == 'd' && direction != 3)
			direction = 1;
		// 使用GetAsyncKeyState来实现用F1，F2来加速和减速
		else if (GetAsyncKeyState(VK_F1)) { // F1控制加速并得分
			speedup();
			score += 2;
		} else if (GetAsyncKeyState(VK_F2)) { // F2控制减速并扣分
			speeddown();
			score -= 2;
			if (score < 0)
				score = 0; // 保证得分不为负数
		}
		// 按ESC结束游戏
		else if (ch == '\x1B') { // ESC键控制游戏结束
			gameOver = 1;
		}
	}

	Sleep(speed);
	snakemove();
}

void endGame() {
	system("cls");
	printf("游戏结束!\n");
	printf("你的得分: %d\n", score);
	if (score > highScore) {
		highScore = score;
		FILE *file = fopen("save.txt", "w");
		fprintf(file, "%d", highScore);
		fclose(file);
		printf("创纪录啦！最高分被你刷新啦，真棒！！！\n");
	} else {
		printf("最高分数: %d\n", highScore);
	}
	printf("按 1 重新开始游戏 或按 2 退出游戏\n");
	char ch = _getch();
	if (ch == '1') {
		resetGame();
		welcometogame();
	} else if (ch == '2') {
		exit(0);
	} else {
		printf("输入错误，重新选择： 按 1 重新开始游戏 或按 2 退出游戏\n");
		_getch();
	}
}

//重置游戏设置
void resetGame() {
	score = 0;
	snakeLength = 1;
	direction = 1;
	gameOver = 0;
	speed = 200;
}

// 游戏规则界面设置
void showInstructions() {
	system("cls");
	printf("游戏帮助:\n");
	printf("=====================\n");
	printf("贪吃蛇游戏是一款老少皆宜，深受人们喜爱的小游戏。\n");
	printf("在我们的游戏中，你将成为一条年幼的蟒蛇，在危机重重的亚马逊丛林中寻找新鲜美味儿的水果（fruit），吃下它，并逐渐成长为一条真正的蟒（man）蛇王。\n");
	printf("规则如下：\n");
	printf("1.使用'w''a''s''d'实现上下左右移动。\n");
	printf("2.当你吃下水果后，你的速度会变快。\n");
	printf("3.使用’F1‘可以实现加速并得分+2；使用’F2‘可以实现减速并得分-2。\n");
	printf("4.当速度不超过320时吃到食物得分为2；当速度超过320时吃到食物得分为1。\n");
	printf("5.当你触碰到游戏边界或者咬到自己时，游戏结束，你也可以通过在游戏中使用’esc‘键来结束游戏。\n");
	printf("=====================\n");
	printf("最后，希望你能玩得开心，谢谢你玩我们的游戏。\n");
	printf("\n");
	printf("by郝煜坤and梁文麒\n");
	printf("按任意键返回...\n");
	_getch();
	welcometogame();
}

int main() {
	srand(time(0));
	welcometogame();
	return 0;
}